import gbk from './printUtil-GBK.js'
import * as zksdk from './bluetoolth.js'
import {
	getSharePoster
} from './QS-SharePoster/QS-SharePoster.js'

const errMsg = {
	10000: '未初始化蓝牙模块',
	10001: '蓝牙未打开',
	10002: '没有找到指定设备',
	10003: '连接失败',
	10004: '没有找到指定服务',
	10005: '没有找到指定特征值',
	10006: '当前连接已断开',
	10007: '当前特征值不支持此操作',
	10008: '系统上报异常',
	10009: '系统版本低于 4.3 不支持BLE'
};

let _this;

export class Printer {
	constructor(arg) {
		this.devices = []; // 搜索到的蓝牙列表
		this.connId = ''; // 已连接的蓝牙id
		this.currDev = null; // 已连接的蓝牙
		this.services = []; // 当前蓝牙链接的所有服务
		this.serviceId = ''; // 当前蓝牙链接的服务id
		this.writeId = ''; // 写入特征值
		this.readId = ''; // 读取特征值
		this.isOpen = false; // 蓝牙模块是否打开
		_this = this; // 实例的this指向
		this.connected = false; // 是否处于已连接状态
		this.deviceId = ''; //链接id
	}

	/**
	 * @description 初始化
	 */
	async init() {
		if (this.isOpen) await this.closeBluetoothAdapter();
		this.deviceId = ''
		uni.openBluetoothAdapter({
			success: res => {
				console.log('初始化蓝牙模块成功');
				this.isOpen = true;
				this.startBluetoothDevicesDiscovery();
				uni.onBluetoothDeviceFound(devices => {
					this.getBluetoothDevices();
				});
			},
			fail: err => {
				console.log('初始化蓝牙模块失败：' + errMsg[err.code]);
			}
		});

		uni.onBLEConnectionStateChange(res => {
			this.connected = res.connected;
			uni.$emit('onBLEConnectionStateChange', res);
		})
	}



	/**
	 * @description 开始扫描蓝牙设备
	 */
	startBluetoothDevicesDiscovery() {
		uni.startBluetoothDevicesDiscovery({
			success: res => {
				console.log('成功获取蓝牙列表', res);
			}
		});
	}

	/**
	 * @description 关闭蓝牙模块
	 */
	closeBluetoothAdapter() {
		return new Promise((resolve, reject) => {
			uni.closeBluetoothAdapter({
				complete: (res) => {
					resolve(res)
				}
			})
		})
	}

	/**
	 * @description 获取在蓝牙模块生效期间所有已发现的蓝牙设备。包括已经和本机处于连接状态的设备。
	 */
	getBluetoothDevices() {
		uni.getBluetoothDevices({
			success: res => {
				this.devices = res.devices.filter(item => item.name);
				uni.$emit('onDevicesRes', {
					data: this.devices,
					msg: '所有已发现的蓝牙设备'
				})
			}
		});
	}

	/**
	 * @description 链接蓝牙设备
	 * @param {Object} item
	 * @param {Object} index
	 */
	linkDevice(item, index) {
		this.deviceId = item.deviceId
		let deviceId = item.deviceId;
		uni.showLoading({
			title: '连接中',
			mask: true
		})
		uni.createBLEConnection({
			deviceId: item.deviceId,
			timeout: 10000,
			success: res => {
				this.connId = deviceId;
				this.currDev = item;
				global.connId = deviceId;
				global.currDev = item;
				uni.hideLoading();
				uni.showToast({
					title: '连接蓝牙成功,您可以开始打印了~',
					icon: 'success',
					position: 'bottom'
				});
				setTimeout(() => {
					this.getServicesSuccess(deviceId);
				}, 1000);
			},
			fail: err => {
				uni.hideLoading();
				uni.showToast({
					title: '链接失败' + errMsg[err.code],
					icon: 'none',
					position: 'bottom'
				});
				console.log(err);
				console.log('操作失败：' + errMsg[err.code]);
			}
		});
	}

	/**
	 * @description 获取蓝牙设备所有服务
	 * @param {Object} deviceId
	 */
	getServicesSuccess(deviceId) {
		uni.getBLEDeviceServices({
			deviceId: deviceId,
			success: res => {
				console.log('getServicesSuccess', res);
				this.services = res.services;
				zksdk.getDeviceCharacteristics(deviceId, this.services, this.onGetCharacterSuccess, this
					.onGetCharacterFail);
			}
		});
	}

	/**
	 * @description 特征值（Characteristics）获取成功
	 * @param {Object} res
	 */
	onGetCharacterSuccess(res) {
		console.log('onGetCharacterSuccess servid ', res.serviceId);
		console.log('write character ', res.writeId);
		console.log('read character ', res.readId);
		console.log('this', _this);
		_this.serviceId = res.serviceId;
		_this.writeId = res.writeId;
		_this.readId = res.readId;
		//---停止扫描蓝牙设备---------
		uni.stopBluetoothDevicesDiscovery()
	}

	/**
	 * @description 数据全部发送成功回调
	 */
	onSendSuccess() {
		console.log("onSendSuccess");
	}

	/**
	 * @description 打印打印电子面单
	 * @param {String} title 公司名称
	 * @param {String} cstn 客户电话
	 * @param {String} barCode 条码内容
	 * @param {String} barCode2 右侧条码内容
	 * @param {String} por 收货地
	 * @param {String} rgName 收货人姓名 
	 * @param {String} rgMobile 收货人电话 
	 * @param {String} rgAdd 收货地址
	 * @param {String} rgDetailAdd 详细收货地址
	 * @param {String} dgName 发货人姓名
	 * @param {String} dgMobile 发货人电话
	 * @param {String} dgAdd 发货地址
	 * @param {String} dgDetailAdd 详细发货地址
	 * @param {String} remarks 备注
	 * @param {String} time 时间
	 * @param {String} qRCode 小程序二维码
	 */
	async printFaceSheet({
		title,
		cstn,
		barCode,
		barCode2,
		por,
		rgName,
		rgMobile,
		rgAdd,
		rgDetailAdd,
		dgName,
		dgMobile,
		dgAdd,
		dgDetailAdd,
		remarks,
		time,
		qRCode
	}) {
		if (!this.connected) {
			
			return uni.showToast({
				title: '未连接打印机',
				icon: 'none'
			})
		}

		title = title || 'MINI';
		cstn = cstn || '903211'
		por = por || '柯桥收'
		remarks = remarks || '无';
		time = time || this.dateFormat(new Date().getTime(), 'second');

		let offset = 0; //偏移量
		// 创建打印页面
		let strStart = zksdk.CreatCPCLPage(576, 610, 1);

		// 具体打印内容-开始
		let strContent = zksdk.addCPCLLocation(0)
		strContent += zksdk.addCPCLLine(0, 0, 576, 0, 1);
		strContent += zksdk.addCPCLSETBOLD(1)
		strContent += zksdk.addCPCLText(300, 20, '24', 12, 0, title);
		strContent += zksdk.addCPCLSETBOLD(0)
		strContent += zksdk.addCPCLText(300, 60, '0', 20, 0, '隔日');

		strContent += zksdk.addCPCLText(10, 110, '24', 7, 0, barCode);
		strContent += zksdk.addCPCLText(10, 140, '24', 7, 0, '始');
		strContent += zksdk.addCPCLText(40, 140, '24', 7, 0, rgDetailAdd);
		
		// strContent += zksdk.addCPCLText(240, 110, '24', 9, 0, '目的');
		let mText = this.handleTxtLineFeed(1, '目的', 30, 270, 110, '24', 7, 0)
		strContent += mText.strs;
		strContent += zksdk.addCPCLText(320, 110, '24', 7, 0, dgName);
		strContent += zksdk.addCPCLText(320, 140, '24', 7, 0, dgName);
		
		strContent += zksdk.addCPCLLine(0, 180, 576, 180, 1);
		
		// strContent += zksdk.addCPCLText(20, 160, '24', 7, 0, '签单要求');
		let mText5 = this.handleTxtLineFeed(2, '签单要求', 30, 20, 200, '24', 15, 0)
		strContent += mText5.strs;
		
		strContent += zksdk.addCPCLLine(130, 200, 150, 200, 1);
		strContent += zksdk.addCPCLLine(130, 200, 130, 220, 1);
		strContent += zksdk.addCPCLLine(130, 220, 150, 220, 1);
		strContent += zksdk.addCPCLLine(150, 200, 150, 220, 1);
		strContent += zksdk.addCPCLText(160, 200, '24', 7, 0, '签名/日期');
		
		strContent += zksdk.addCPCLLine(330, 200, 350, 200, 1);
		strContent += zksdk.addCPCLLine(330, 200, 330, 220, 1);
		strContent += zksdk.addCPCLLine(330, 220, 350, 220, 1);
		strContent += zksdk.addCPCLLine(350, 200, 350, 220, 1);
		strContent += zksdk.addCPCLText(360, 200, '24', 7, 0, '身份证号');
		
		strContent += zksdk.addCPCLLine(130, 240, 150, 240, 1);
		strContent += zksdk.addCPCLLine(130, 240, 130, 260, 1);
		strContent += zksdk.addCPCLLine(130, 260, 150, 260, 1);
		strContent += zksdk.addCPCLLine(150, 240, 150, 260, 1);
		strContent += zksdk.addCPCLText(160, 240, '24', 7, 0, '盖章');
		
		strContent += zksdk.addCPCLLine(330, 240, 350, 240, 1);
		strContent += zksdk.addCPCLLine(330, 240, 330, 260, 1);
		strContent += zksdk.addCPCLLine(330, 260, 350, 260, 1);
		strContent += zksdk.addCPCLLine(350, 240, 350, 260, 1);
		strContent += zksdk.addCPCLText(360, 240, '24', 7, 0, '其他要求');
		// strContent += zksdk.addCPCLBarCode(10, 80, '128', 100, 0, 2, 4, barCode);

		strContent += zksdk.addCPCLLocation(0)
		// strContent += zksdk.addCPCLText(490, 200, '24', 7, 3, barCode2);
		// strContent += zksdk.addCPCLBarCode(500, 360, '128', 70, 1, 1, 2, barCode2);
		// strContent += zksdk.addCPCLLine(462, 0, 462, 390, 1);
		// strContent += zksdk.addCPCLLine(462, 390, 576, 390, 1);
		strContent += zksdk.addCPCLLine(0, 280, 576, 280, 1);
  
		// 收货人信息-开始
		strContent += zksdk.addCPCLSETMAG(3, 3);
		// strContent += zksdk.addCPCLText(10, 300, '24', 7, 0, por);
		strContent += zksdk.addCPCLSETMAG(1, 1);
		strContent += zksdk.addCPCLSETBOLD(1)
		strContent += zksdk.addCPCLText(10, 300, '24', 6, 0, '收件人：');
		strContent += zksdk.addCPCLText(140, 300, '24', 11, 0, rgName);
		strContent += zksdk.addCPCLSETBOLD(0) 
		strContent += zksdk.addCPCLText(300, 300, '24', 7, 0, '电话');
		strContent += zksdk.addCPCLText(360, 300, '24', 7, 0, rgMobile);
		strContent += zksdk.addCPCLText(10, 350, '24', 6, 0, '地址：');
		// strContent += zksdk.addCPCLText(100, 450, '24', 7, 0, rgAdd);
		let mText1 = this.handleTxtLineFeed(18, rgAdd, 30, 100, 350, '24', 7, 0)
		strContent += mText1.strs;
		// offset += mText1.height;
		// strContent += zksdk.addCPCLLine(0, 530 + offset, 576, 530 + offset, 1);
		// 收货人信息-结束
		strContent += zksdk.addCPCLLine(0, 420, 576, 420, 1);
		
		
		
		dgAdd.forEach((item,i)=>{
			strContent += zksdk.addCPCLText(30 + i*100, 430, '24', 6, 0, item);
		})
		
		// for (i = 0; i < dgAdd.length; i++) { 
		   
		//    // strContent += zksdk.addCPCLText(130, 430, '24', 6, 0, '郑州');
		//    // strContent += zksdk.addCPCLText(230, 430, '24', 6, 0, '新乡');
		//  }
		
		
		// strContent += zksdk.addCPCLText(30, 430, '24', 6, 0, '虎门');
		// strContent += zksdk.addCPCLText(130, 430, '24', 6, 0, '郑州');
		// strContent += zksdk.addCPCLText(230, 430, '24', 6, 0, '新乡');
		
		dgDetailAdd.forEach((item,i)=>{
			strContent += zksdk.addCPCLText(30 + i*100, 480, '24', 6, 0, item);
		})
		// strContent += zksdk.addCPCLText(30, 480, '24', 6, 0, 'A207');
		// strContent += zksdk.addCPCLText(130, 480, '24', 6, 0, 'A208');
		// strContent += zksdk.addCPCLText(230, 480, '24', 6, 0, 'A209');
		
		
		
		strContent += zksdk.addCPCLLine(0, 515, 576, 515, 1);
		// 备注-开始
		// strContent += zksdk.addCPCLSETBOLD(1)
		// strContent += zksdk.addCPCLText(10, 550 + offset, '24', 6, 0, '备注：');
		// strContent += zksdk.addCPCLSETBOLD(0)
		let mText3 = this.handleTxtLineFeed(10, por, 30, 30, 530 + offset, '24', 7, 0)
		strContent += mText3.strs;
		// offset += mText3.height;
		// strContent += zksdk.addCPCLLine(0, 570 + offset, 576, 570 + offset, 1);
    console.log('-------------------------------------------------------------')
		// 备注-结束

		// 二维码-开始
		// let qr = await this.handleImg(0,580 + offset,{
		// 	width: 110,
		// 	height: 110,
		// 	threshold: 1
		// }, '/static/select.png', 1)
		// strContent += qr.data;
		// strContent += zksdk.addCPCLSETBOLD(2)
		// let mText4 = this.handleTxtLineFeed(7, '扫一扫，关注公众号或者小程序 ，实时了解包裹动态', 30, 202, 610 + offset, '24', 7, 0)
		// strContent += mText4.strs;
		// strContent += zksdk.addCPCLSETBOLD(0)
		// strContent += zksdk.addCPCLQRCode(20, 580 + offset, 'Q', 2, 4,
		// 	'http://weixin.qq.com/r/WB0XD7LE-O_DrfZs90hK?xxxxxz=css');
		// strContent += zksdk.addCPCLText(60, 740 + offset, '24', 6, 0, '公众号');
		// strContent += zksdk.addCPCLQRCode(405, 580 + offset, 'Q', 2, 4,
		// 	'https://mp.weixin.qq.com/a/~32ZQX9kLwabY5xCqoUlPJA~~');
		// strContent += zksdk.addCPCLText(444, 740 + offset, '24', 6, 0, '小程序');
		// strContent += zksdk.addCPCLLine(0, 770 + offset, 576, 770 + offset, 1);
		// strContent += zksdk.addCPCLLine(192, 570 + offset, 192, 770 + offset, 1);
		// strContent += zksdk.addCPCLLine(384, 570 + offset, 384, 770 + offset, 1);
		// // 二维码-结束

		// strContent += zksdk.addCPCLLine(0, 0, 0, 770 + offset, 1);
		// strContent += zksdk.addCPCLLine(575, 0, 575, 770 + offset, 1);
		// strContent += zksdk.addCPCLLocation(1)
		// strContent += zksdk.addCPCLText(10, 950, '24', 7, 0, '打印时间：' + time);
		// 具体打印内容-开始

		console.log(strContent);
		// 添加标签缝隙定位指令
		let strEnd = zksdk.addCPCLGAP();
		// 添加打印指令
		strEnd += zksdk.addCPCLPrint();

		var byteStart = gbk.strToGBKByte(strStart);
		var byte1 = gbk.strToGBKByte(strContent);
		var byteEnd = gbk.strToGBKByte(strEnd);

		var bytes = new ArrayBuffer(byteStart.byteLength + byte1.byteLength + byteEnd.byteLength);
		var dv = new DataView(bytes);

		var dvStart = new DataView(byteStart);
		var dv1 = new DataView(byte1);
		var dvEnd = new DataView(byteEnd);

		for (var i = 0; i < byteStart.byteLength; i++) {
			dv.setInt8(i, dvStart.getInt8(i));
		}

		for (var i = 0; i < byte1.byteLength; i++) {
			dv.setInt8(byteStart.byteLength + i, dv1.getInt8(i));
		}

		for (var i = 0; i < byteEnd.byteLength; i++) {
			dv.setInt8(byteStart.byteLength + byte1.byteLength + i, dvEnd.getInt8(i));
		}

		var datalen = 20;

		// return console.log(bytes.byteLength);

		const opt = {
			deviceId: this.connId,
			serviceId: this.serviceId,
			characteristicId: this.writeId,
			value: bytes,
			lasterSuccess: this.onSendSuccess,
			onceLength: datalen
		};

		// 发送打印指令
		zksdk.sendDataToDevice(opt);
	}

	/**
	 * @description 处理字符串换行
	 * @param {Number} step 多少个字符添加换行
	 * @param {string} str 要换行的长字符串
	 * @param {Number} height 行高
	 */
	handleTxtLineFeed(step, str, height, x, y, fontName, fontSize, rotation) {
		let steps = Math.floor(str.length / step);
		let remainder = str.length % step;
		let strs = [];
		for (let i = 0; i < steps; i++) {
			strs.push(str.slice(i * step, (i + 1) * step))
		}
		if (remainder) strs.push(str.slice(steps * step, steps * step + remainder));
		console.log(strs);
		strs = strs.map((item, index) => {
			return zksdk.addCPCLText(x, (height * index) + y, fontName, fontSize, rotation, item)
		})
		return {
			strs: strs.join(''),
			steps: strs.length,
			height: strs.length * height
		};
	}

	/**
	 * @description 处理打印图片
	 * @param {Object} x
	 * @param {Object} y
	 * @param {Object} data
	 */
	handleImg(x, y, data, src, zoom) {
		zoom = zoom || 1;
		return new Promise((resolve, reject) => {
			getSharePoster({
				posterCanvasId: 'print-canvas',
				background: {
					width: 1500,
					height: 1500,
				},
				drawArray: () => {
					return [{
						type: 'image',
						url: src,
						dx: 0,
						dy: 0,
						dWidth: data.width * zoom,
						dHeight: data.height * zoom,
					}]
				}
			}).then(() => {
				uni.canvasGetImageData({
					canvasId: 'print-canvas',
					x: 0,
					y: 0,
					width: data.width * zoom,
					height: data.height * zoom,
					success: res => {
						let strCmd = zksdk.addCPCLImageCmd(x, y, {
							imageData: res.data,
							width: data.width,
							height: data.height,
							threshold: data.threshold
						})

						console.log('二维码', res.data);
						resolve({
							code: 1,
							msg: '图片数据生成成功',
							data: strCmd
						})
					},
					fail: (err) => {
						reject({
							code: 0,
							msg: '图片图片数据生成失败'
						})
					}
				})

				// uni.canvasToTempFilePath({
				// 	canvasId:'print-canvas',
				// 	y: 0,
				// 	x: 0,
				// 	width: data.width,
				// 	height: data.height,
				// 	destWidth: data.width,
				// 	destHeight: data.height,
				// 	success:res=>{
				// 		resolve({code:1,msg:'图片生成成功',data:res.tempFilePath})
				// 	},
				// 	fail: (err) => {
				// 		reject({code:0,msg:'图片生成失败'})
				// 	}
				// })
			})
		})
	}

	/**
	 * @description 处理时间戳
	 * @param {Object} dataStr
	 * @param {Object} type
	 * @param {Object} format
	 */
	dateFormat(dataStr, type, format) {
		if (!dataStr) return '';

		function timeAdd0(str) {
			if (str < 10) {
				str = '0' + str;
			}
			return str
		}

		let formats = [];

		dataStr = dataStr.length == 10 ? dataStr * 1000 : dataStr;
		type = type || 'day';
		format = format || 'YY.MM.DD hh:mm:ss';
		formats = format.split(/[YY|MM|DD|hh|mm|ss]/g).filter(item => item == ' ' || item);
		// //console.log(formats)
		let time = new Date(Number(dataStr));

		let y = time.getFullYear();
		let m = timeAdd0(time.getMonth() + 1);
		let d = timeAdd0(time.getDate());
		let h = timeAdd0(time.getHours());
		let mm = timeAdd0(time.getMinutes());
		let s = timeAdd0(time.getSeconds());

		let res = '';

		switch (type) {
			case 'day':
				res = [y, formats[0], m, formats[1], d].join('');
				break;
			case 'minute':
				res = [y, formats[0], m, formats[1], d, formats[2], h, formats[3], mm].join('');
				break;
			case 'second':
				res = [y, formats[0], m, formats[1], d, formats[2], h, formats[3], mm, formats[4], s].join('');
				break;
			default:
				break;
		}

		return res;
	}

}
